﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Blackbird.Common.Utility;
using Blackbird.Core.Editable.Frames;
using Microsoft.Win32;
using Path = System.IO.Path;

namespace Blackbird.Dev.Utility {
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class MainWindow {
        private readonly FontFamilyList _fonts;

        public MainWindow() {
            InitializeComponent();
            _fonts = new FontFamilyList();
        }

        public bool SuspendPreviewGeneration { get; set; }

        public FontFamily SelectedFontFamily {
            get { return (FontFamily)FontFamilyComboBox.SelectedValue; }
            set { FontFamilyComboBox.SelectedValue = value; }
        }

        public FontStyle SelectedFontStyle {
            get { return (FontStyle)FontStyleComboBox.SelectedValue; }
            set { FontStyleComboBox.SelectedValue = value; }
        }

        public FontWeight SelectedFontWeight {
            get { return (FontWeight)FontWeightComboBox.SelectedValue; }
            set { FontWeightComboBox.SelectedValue = value; }
        }

        public FontStretch SelectedFontStretch {
            get { return (FontStretch)FontStretchComboBox.SelectedValue; }
            set { FontStretchComboBox.SelectedValue = value; }
        }

        public Brush SelectedTextBrush {
            get { return (Brush)((ComboBoxItem)TextColorComboBox.SelectedItem).Tag; }
            set { SelectColorByTagValue(TextColorComboBox, value); }
        }

        public Brush SelectedBackgroundBrush {
            get { return (Brush)((ComboBoxItem)BackgroundColorComboBox.SelectedItem).Tag; }
            set { SelectColorByTagValue(BackgroundColorComboBox, value); }
        }

        public string SelectedText {
            get { return ImageTextTextBox.Text; }
            set { ImageTextTextBox.Text = value; }
        }

        public double SelectedFontSize {
            get {
                double size;
                return double.TryParse(FontSizeTextBox.Text, out size) ? size : 96.0;
            }
            set { FontSizeTextBox.Text = value.ToString(CultureInfo.CurrentCulture); }
        }

        private void TabControlLoaded(object sender, RoutedEventArgs e) {
            // Load the controls with vialble options
            //Load up the Font Styles...
            PopulateByProperty<Brush>(typeof(Brushes), TextColorComboBox);
            PopulateByProperty<Brush>(typeof(Brushes), BackgroundColorComboBox);

            SuspendPreviewGeneration = true;
            try {
                SelectedFontFamily = _fonts["Consolas"];
                SelectedFontStyle = FontStyles.Normal;
                SelectedFontWeight = FontWeights.Normal;
                SelectedFontStretch = FontStretches.Normal;
                SelectedTextBrush = Brushes.Black;
                SelectedBackgroundBrush = Brushes.White;
            } finally {
                SuspendPreviewGeneration = false;
                RegeneratePreview();
            }
        }

        private void RegeneratePreview() {
            if (!SuspendPreviewGeneration) {
                RenderToCanvas(GetImageText("x", "y"));
            }
        }

        private string GetImageText(object x, object y) {
            string imageText = SelectedText;
            var parameters = new List<object>();

            if (imageText.Contains("{0}"))
                parameters.Add(x);

            if (imageText.Contains("{1}"))
                parameters.Add(y);
            return string.Format(imageText, parameters.ToArray());
        }

        private FormattedText GenerateText(string imageText) {
            Typeface typeface = GenerateTypeface();
            return new FormattedText(imageText, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface,
                                         SelectedFontSize, SelectedTextBrush) { MaxTextWidth = 246, MaxTextHeight = 246 };
        }

        private static Point GetTextOrigin(FormattedText text) {
            return new Point {
                X = (128.0) - (text.Width / 2.0),
                Y = (128.0) - (text.Height / 2.0)
            };
        }

        private void RenderText(DrawingContext context, FormattedText text, Point origin) {
            context.DrawRectangle(SelectedBackgroundBrush, new Pen(SelectedTextBrush, 1.0), new Rect(5, 5, 250, 250));
            context.DrawText(text, origin);
        }

        private void RenderToCanvas(string imageText) {
            var text = GenerateText(imageText);
            var origin = GetTextOrigin(text);

            var group = new DrawingGroup();

            using (DrawingContext context = group.Open()) {
                RenderText(context, text, origin);
            }

            var brush = new DrawingBrush(group);
            var rect = new Rectangle {
                Fill = brush,
                Width = 256,
                Height = 256
            };

            DisplayCanvas.Children.Clear();
            DisplayCanvas.Children.Add(rect);
            Canvas.SetTop(rect, 0.0);
            Canvas.SetLeft(rect, 0.0);
        }

        private Typeface GenerateTypeface() {
            return new Typeface(SelectedFontFamily, SelectedFontStyle, SelectedFontWeight, SelectedFontStretch);
        }

        private void PopulateByProperty<T>(Type type, ComboBox combo) {
            PropertyInfo[] properties = type.GetProperties(BindingFlags.Static | BindingFlags.Public);
            foreach (PropertyInfo property in properties) {
                object value = property.GetValue(null, null);
                if ((value != null) && (value is T)) {
                    combo.Items.Add(new ComboBoxItem {
                        Content = property.Name,
                        Tag = value
                    });
                }
            }
        }

        private void SelectColorByTagValue(ComboBox combo, Brush value) {
            foreach (int idx in from ComboBoxItem item in combo.Items where (item.Tag).ToString() == value.ToString() select combo.Items.IndexOf(item)) {
                combo.SelectedIndex = idx;
                return;
            }
        }

        private void TextBoxLostFocus(object sender, RoutedEventArgs e) {
            RegeneratePreview();
        }

        private void ComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) {
            RegeneratePreview();
        }

        private void GenerateButtonClick(object sender, RoutedEventArgs e) {
            var targetBitmap = new RenderTargetBitmap(256, 256, 96.0, 96.0, PixelFormats.Pbgra32);
            var frameset = new EditableFrameset {
                Name = "SampleFrameset",
                Fps = 32,
                Loop = true
            };
            int count;
            if (int.TryParse(NumberOfFramesTextBox.Text, out count)) {
                for (int i = 0; i < count; i++) {
                    var visual = new DrawingVisual();
                    var text = GenerateText(GetImageText(i + 1, count));
                    var origin = GetTextOrigin(text);
                    using (var context = visual.RenderOpen()) {
                        RenderText(context, text, origin);
                    }
                    targetBitmap.Render(visual);
                    frameset.Add(new EditableFrame {
                        BitmapSource = targetBitmap,
                        Name = string.Format("Frame{0}", i + 1)
                    });
                }
            }

            SerializationUtility.SaveToFile(FilenameTextBox.Text, frameset);
        }

        private void BrowseButtonClick(object sender, RoutedEventArgs e) {
            var saveFileDialog = new SaveFileDialog {
                FileName = FilenameTextBox.Text,
                InitialDirectory = FilenameTextBox.Text,
                Filter = "Frameset Files (*.fst)|*.fst|All Files (*.*)|*.*"
            };

            bool? fileOpened = saveFileDialog.ShowDialog();
            if (fileOpened.Value) {
                FilenameTextBox.Text = saveFileDialog.FileName;
            }
        }
    }
}